package net.minecraft.world.gen.feature;

import com.google.common.collect.Lists;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLog;
import net.minecraft.block.material.Material;
import net.minecraft.init.Blocks;
import net.minecraft.util.BlockPos;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;

public class WorldGenBigTree extends WorldGenAbstractTree
{
    private Random field_175949_k;
    private World field_175946_l;
    private BlockPos field_175947_m;
    int heightLimit;
    int height;
    double heightAttenuation;
    double field_175944_d;
    double field_175945_e;
    double leafDensity;
    int field_175943_g;
    int field_175950_h;

    /**
     * Sets the distance limit for how far away the generator will populate leaves from the base leaf node.
     */
    int leafDistanceLimit;
    List field_175948_j;
    private static final String __OBFID = "CL_00000400";

    public WorldGenBigTree(boolean p_i2008_1_)
    {
        super(p_i2008_1_);
        this.field_175947_m = BlockPos.ORIGIN;
        this.heightAttenuation = 0.618D;
        this.field_175944_d = 0.381D;
        this.field_175945_e = 1.0D;
        this.leafDensity = 1.0D;
        this.field_175943_g = 1;
        this.field_175950_h = 12;
        this.leafDistanceLimit = 4;
    }

    /**
     * Generates a list of leaf nodes for the tree, to be populated by generateLeaves.
     */
    void generateLeafNodeList()
    {
        this.height = (int)((double)this.heightLimit * this.heightAttenuation);

        if (this.height >= this.heightLimit)
        {
            this.height = this.heightLimit - 1;
        }

        int var1 = (int)(1.382D + Math.pow(this.leafDensity * (double)this.heightLimit / 13.0D, 2.0D));

        if (var1 < 1)
        {
            var1 = 1;
        }

        int var2 = this.field_175947_m.getY() + this.height;
        int var3 = this.heightLimit - this.leafDistanceLimit;
        this.field_175948_j = Lists.newArrayList();
        this.field_175948_j.add(new WorldGenBigTree.FoliageCoordinates(this.field_175947_m.offsetUp(var3), var2));

        for (; var3 >= 0; --var3)
        {
            float var4 = this.layerSize(var3);

            if (var4 >= 0.0F)
            {
                for (int var5 = 0; var5 < var1; ++var5)
                {
                    double var6 = this.field_175945_e * (double)var4 * ((double)this.field_175949_k.nextFloat() + 0.328D);
                    double var8 = (double)(this.field_175949_k.nextFloat() * 2.0F) * Math.PI;
                    double var10 = var6 * Math.sin(var8) + 0.5D;
                    double var12 = var6 * Math.cos(var8) + 0.5D;
                    BlockPos var14 = this.field_175947_m.add(var10, (double)(var3 - 1), var12);
                    BlockPos var15 = var14.offsetUp(this.leafDistanceLimit);

                    if (this.func_175936_a(var14, var15) == -1)
                    {
                        int var16 = this.field_175947_m.getX() - var14.getX();
                        int var17 = this.field_175947_m.getZ() - var14.getZ();
                        double var18 = (double)var14.getY() - Math.sqrt((double)(var16 * var16 + var17 * var17)) * this.field_175944_d;
                        int var20 = var18 > (double)var2 ? var2 : (int)var18;
                        BlockPos var21 = new BlockPos(this.field_175947_m.getX(), var20, this.field_175947_m.getZ());

                        if (this.func_175936_a(var21, var14) == -1)
                        {
                            this.field_175948_j.add(new WorldGenBigTree.FoliageCoordinates(var14, var21.getY()));
                        }
                    }
                }
            }
        }
    }

    void func_180712_a(BlockPos p_180712_1_, float p_180712_2_, Block p_180712_3_)
    {
        int var4 = (int)((double)p_180712_2_ + 0.618D);

        for (int var5 = -var4; var5 <= var4; ++var5)
        {
            for (int var6 = -var4; var6 <= var4; ++var6)
            {
                if (Math.pow((double)Math.abs(var5) + 0.5D, 2.0D) + Math.pow((double)Math.abs(var6) + 0.5D, 2.0D) <= (double)(p_180712_2_ * p_180712_2_))
                {
                    BlockPos var7 = p_180712_1_.add(var5, 0, var6);
                    Material var8 = this.field_175946_l.getBlockState(var7).getBlock().getMaterial();

                    if (var8 == Material.air || var8 == Material.leaves)
                    {
                        this.func_175905_a(this.field_175946_l, var7, p_180712_3_, 0);
                    }
                }
            }
        }
    }

    /**
     * Gets the rough size of a layer of the tree.
     */
    float layerSize(int p_76490_1_)
    {
        if ((float)p_76490_1_ < (float)this.heightLimit * 0.3F)
        {
            return -1.0F;
        }
        else
        {
            float var2 = (float)this.heightLimit / 2.0F;
            float var3 = var2 - (float)p_76490_1_;
            float var4 = MathHelper.sqrt_float(var2 * var2 - var3 * var3);

            if (var3 == 0.0F)
            {
                var4 = var2;
            }
            else if (Math.abs(var3) >= var2)
            {
                return 0.0F;
            }

            return var4 * 0.5F;
        }
    }

    float leafSize(int p_76495_1_)
    {
        return p_76495_1_ >= 0 && p_76495_1_ < this.leafDistanceLimit ? (p_76495_1_ != 0 && p_76495_1_ != this.leafDistanceLimit - 1 ? 3.0F : 2.0F) : -1.0F;
    }

    void func_175940_a(BlockPos p_175940_1_)
    {
        for (int var2 = 0; var2 < this.leafDistanceLimit; ++var2)
        {
            this.func_180712_a(p_175940_1_.offsetUp(var2), this.leafSize(var2), Blocks.leaves);
        }
    }

    void func_175937_a(BlockPos p_175937_1_, BlockPos p_175937_2_, Block p_175937_3_)
    {
        BlockPos var4 = p_175937_2_.add(-p_175937_1_.getX(), -p_175937_1_.getY(), -p_175937_1_.getZ());
        int var5 = this.func_175935_b(var4);
        float var6 = (float)var4.getX() / (float)var5;
        float var7 = (float)var4.getY() / (float)var5;
        float var8 = (float)var4.getZ() / (float)var5;

        for (int var9 = 0; var9 <= var5; ++var9)
        {
            BlockPos var10 = p_175937_1_.add((double)(0.5F + (float)var9 * var6), (double)(0.5F + (float)var9 * var7), (double)(0.5F + (float)var9 * var8));
            BlockLog.EnumAxis var11 = this.func_175938_b(p_175937_1_, var10);
            this.func_175903_a(this.field_175946_l, var10, p_175937_3_.getDefaultState().withProperty(BlockLog.AXIS_PROP, var11));
        }
    }

    private int func_175935_b(BlockPos p_175935_1_)
    {
        int var2 = MathHelper.abs_int(p_175935_1_.getX());
        int var3 = MathHelper.abs_int(p_175935_1_.getY());
        int var4 = MathHelper.abs_int(p_175935_1_.getZ());
        return var4 > var2 && var4 > var3 ? var4 : (var3 > var2 ? var3 : var2);
    }

    private BlockLog.EnumAxis func_175938_b(BlockPos p_175938_1_, BlockPos p_175938_2_)
    {
        BlockLog.EnumAxis var3 = BlockLog.EnumAxis.Y;
        int var4 = Math.abs(p_175938_2_.getX() - p_175938_1_.getX());
        int var5 = Math.abs(p_175938_2_.getZ() - p_175938_1_.getZ());
        int var6 = Math.max(var4, var5);

        if (var6 > 0)
        {
            if (var4 == var6)
            {
                var3 = BlockLog.EnumAxis.X;
            }
            else if (var5 == var6)
            {
                var3 = BlockLog.EnumAxis.Z;
            }
        }

        return var3;
    }

    void func_175941_b()
    {
        Iterator var1 = this.field_175948_j.iterator();

        while (var1.hasNext())
        {
            WorldGenBigTree.FoliageCoordinates var2 = (WorldGenBigTree.FoliageCoordinates)var1.next();
            this.func_175940_a(var2);
        }
    }

    /**
     * Indicates whether or not a leaf node requires additional wood to be added to preserve integrity.
     */
    boolean leafNodeNeedsBase(int p_76493_1_)
    {
        return (double)p_76493_1_ >= (double)this.heightLimit * 0.2D;
    }

    void func_175942_c()
    {
        BlockPos var1 = this.field_175947_m;
        BlockPos var2 = this.field_175947_m.offsetUp(this.height);
        Block var3 = Blocks.log;
        this.func_175937_a(var1, var2, var3);

        if (this.field_175943_g == 2)
        {
            this.func_175937_a(var1.offsetEast(), var2.offsetEast(), var3);
            this.func_175937_a(var1.offsetEast().offsetSouth(), var2.offsetEast().offsetSouth(), var3);
            this.func_175937_a(var1.offsetSouth(), var2.offsetSouth(), var3);
        }
    }

    void func_175939_d()
    {
        Iterator var1 = this.field_175948_j.iterator();

        while (var1.hasNext())
        {
            WorldGenBigTree.FoliageCoordinates var2 = (WorldGenBigTree.FoliageCoordinates)var1.next();
            int var3 = var2.func_177999_q();
            BlockPos var4 = new BlockPos(this.field_175947_m.getX(), var3, this.field_175947_m.getZ());

            if (this.leafNodeNeedsBase(var3 - this.field_175947_m.getY()))
            {
                this.func_175937_a(var4, var2, Blocks.log);
            }
        }
    }

    int func_175936_a(BlockPos p_175936_1_, BlockPos p_175936_2_)
    {
        BlockPos var3 = p_175936_2_.add(-p_175936_1_.getX(), -p_175936_1_.getY(), -p_175936_1_.getZ());
        int var4 = this.func_175935_b(var3);
        float var5 = (float)var3.getX() / (float)var4;
        float var6 = (float)var3.getY() / (float)var4;
        float var7 = (float)var3.getZ() / (float)var4;

        if (var4 == 0)
        {
            return -1;
        }
        else
        {
            for (int var8 = 0; var8 <= var4; ++var8)
            {
                BlockPos var9 = p_175936_1_.add((double)(0.5F + (float)var8 * var5), (double)(0.5F + (float)var8 * var6), (double)(0.5F + (float)var8 * var7));

                if (!this.func_150523_a(this.field_175946_l.getBlockState(var9).getBlock()))
                {
                    return var8;
                }
            }

            return -1;
        }
    }

    public void func_175904_e()
    {
        this.leafDistanceLimit = 5;
    }

    public boolean generate(World worldIn, Random p_180709_2_, BlockPos p_180709_3_)
    {
        this.field_175946_l = worldIn;
        this.field_175947_m = p_180709_3_;
        this.field_175949_k = new Random(p_180709_2_.nextLong());

        if (this.heightLimit == 0)
        {
            this.heightLimit = 5 + this.field_175949_k.nextInt(this.field_175950_h);
        }

        if (!this.validTreeLocation())
        {
            return false;
        }
        else
        {
            this.generateLeafNodeList();
            this.func_175941_b();
            this.func_175942_c();
            this.func_175939_d();
            return true;
        }
    }

    /**
     * Returns a boolean indicating whether or not the current location for the tree, spanning basePos to to the height
     * limit, is valid.
     */
    private boolean validTreeLocation()
    {
        Block var1 = this.field_175946_l.getBlockState(this.field_175947_m.offsetDown()).getBlock();

        if (var1 != Blocks.dirt && var1 != Blocks.grass && var1 != Blocks.farmland)
        {
            return false;
        }
        else
        {
            int var2 = this.func_175936_a(this.field_175947_m, this.field_175947_m.offsetUp(this.heightLimit - 1));

            if (var2 == -1)
            {
                return true;
            }
            else if (var2 < 6)
            {
                return false;
            }
            else
            {
                this.heightLimit = var2;
                return true;
            }
        }
    }

    static class FoliageCoordinates extends BlockPos
    {
        private final int field_178000_b;
        private static final String __OBFID = "CL_00002001";

        public FoliageCoordinates(BlockPos p_i45635_1_, int p_i45635_2_)
        {
            super(p_i45635_1_.getX(), p_i45635_1_.getY(), p_i45635_1_.getZ());
            this.field_178000_b = p_i45635_2_;
        }

        public int func_177999_q()
        {
            return this.field_178000_b;
        }
    }
}
